import logging
from logging.handlers import RotatingFileHandler
from flask import Flask, render_template
from flask import g
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
from redis import StrictRedis
from flask_wtf.csrf import CSRFProtect, generate_csrf
from config import config_dict
from info.utitls.common import set_rank_class, user_login_data

# 项目初始化配置放到业务处理包的__init__函数里面
#  2.创建数据库对象
#        if app is not None:
#            self.init_app(app)
# 懒加载模式
db = SQLAlchemy()
# 把redis数据库对象放外边是为了方便其他模块调用
# 这个后面的注释的声明对象的类型
redis_store = None  # type:StrictRedis


def set_log(config_class):
    # 设置日志的记录等级
    logging.basicConfig(level=config_class.LOG_LEVEL)  # 调试debug级
    # 创建日志记录器，指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限  最多可以记录10个日志文件
    file_log_handler = RotatingFileHandler("logs/log", maxBytes=10, backupCount=10)
    # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
    # 为刚创建的日志记录器设置日志记录格式
    file_log_handler.setFormatter(formatter)
    # 为全局的日志工具对象（flask app使用的）添加日志记录器
    logging.getLogger().addHandler(file_log_handler)


def create_app(config_name):
    """将app的创建使用工厂的方法封装起来"""
    # 1.创建app对象
    app = Flask(__name__)

    @app.errorhandler(404)
    @user_login_data
    def handler_404(e):
        """ 处理404页面"""
        # 通过装饰器获取用户数据
        user = g.user
        data = {
            "user_info": user.to_dict() if user else None
        }

        return render_template('news/404.html', data=data)
    # 注册过滤器
    app.add_template_filter(set_rank_class, "set_rank_class")
    # 从配置文件config 获取配置信息
    config_class = config_dict[config_name]
    # 设置日志,在这里设置是因为日志设置警告等级需要配置信息
    set_log(config_class)
    app.config.from_object(config_class)
    # 懒加载设计模式 延迟加载设计模式
    # 数据库对象初始化，如果if app is not None:就初始化数据库对象
    db.init_app(app)
    #  3.创建redis 数据库对象 --这也是一种懒加载模式

    global redis_store
    redis_store = StrictRedis(host=config_class.REDIS_HOST, port=config_class.REDIS_port, decode_responses=True)
    # 4. 添加项目防护机制
    CSRFProtect(app)

    # 通过钩子函数 里面有response 来设置cookie
    @app.after_request
    def set_csrf_token(response):
        # 1.生成csrft_token随机值
        csrf_token = generate_csrf()

        response.set_cookie('csrf_token', csrf_token)
        # 返回响应对象
        return response
    # 5.将session 从内粗转存到数据库中

    # 有app的地方才能注册蓝图
    # 6.注册蓝图
    from info.module.index import index_bp  # 避免循环导入的问题
    app.register_blueprint(index_bp)

    # 注册登陆模块蓝图
    from info.module.passpord import passpord_bp
    app.register_blueprint(passpord_bp)

    # 注册新闻详情的蓝图
    from info.module.news import newsdetail_bp
    app.register_blueprint(newsdetail_bp)

    # 注册新闻详情的蓝图
    from info.module.profile import profile_bp
    app.register_blueprint(profile_bp)

    # 注册管理员的蓝图
    from info.module.admin import admin_bp
    app.register_blueprint(admin_bp)

    # 将内存的redis数据转移到redis 数据库
    Session(app)
    return app
